package com.ponhu.ea2.goodsCenter.provider.excel.listener;


import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ponhu.ea2.entity.*;
import com.ponhu.ea2.enums.PropertyTypeEnum;
import com.ponhu.ea2.enums.YesOrNoEnum;
import com.ponhu.ea2.goodsCenter.provider.excel.headers.InventoryAttributeDataHeader;
import com.ponhu.ea2.goodsCenter.provider.service.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

/**
 * 货品属性数据导入方法
 *
 * @author zhaokai
 */
@Slf4j
public class InventoryAttributeDataImportListenter extends AnalysisEventListener<InventoryAttributeDataHeader> {

    /**
     * 每隔5条存储数据库，实际使用中可以3000条，然后清理list ，方便内存回收
     */
    private static final int BATCH_COUNT = 7000;

    List<InventoryAttributeDataHeader> list = new ArrayList<>();

    PhCategoryService phCategoryService;

    PhPropertyService phPropertyService;

    PhPropertyValueService phPropertyValueService;

    PhCategoryPropertyMdService phCategoryPropertyMdService;

    MaterialService materialService;

    PhMaterialPropertyValueMdService phMaterialPropertyValueMdService;

    public InventoryAttributeDataImportListenter(PhCategoryService phCategoryService, PhPropertyService phPropertyService, PhPropertyValueService phPropertyValueService, PhCategoryPropertyMdService phCategoryPropertyMdService, MaterialService materialService, PhMaterialPropertyValueMdService phMaterialPropertyValueMdService) {
        this.phCategoryService = phCategoryService;
        this.phPropertyService = phPropertyService;
        this.phPropertyValueService = phPropertyValueService;
        this.phCategoryPropertyMdService = phCategoryPropertyMdService;
        this.materialService = materialService;
        this.phMaterialPropertyValueMdService = phMaterialPropertyValueMdService;
    }

    @Override
    public void invoke(InventoryAttributeDataHeader attributeDataHeader, AnalysisContext analysisContext) {
        log.info("解析到一条数据:{}", JSON.toJSONString(attributeDataHeader));
        list.add(attributeDataHeader);
        // 达到BATCH_COUNT了，需要去存储一次数据库，防止数据几万条数据在内存，容易OOM
        if (list.size() >= BATCH_COUNT) {
            saveData();
            // 存储完成清理 list
            list.clear();
        }
    }

    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
        // 这里也要保存数据，确保最后遗留的数据也存储到数据库
        saveData();
        log.info("所有数据解析完成！");
    }

    private void saveData() {
        if (CollectionUtils.isNotEmpty(list)) {
            list.stream().forEach(item -> {
                // 分类
                final String className = item.getClassify();
                // 取出分类信息
                List<PhCategory> phCategoryList = getCategoryListByFirstClassName(className);
                List<PhMaterialPropertyValueMd> phMaterialPropertyValueMds = new ArrayList<>();
                if(CollectionUtils.isNotEmpty(phCategoryList)){
                    phCategoryList.stream().forEach(category -> {
                        if (ObjectUtils.isNotEmpty(category)) {
                            final String attributeName = item.getAttributeName();
                            // 处理属性 "同XXX" 数据
                            if (attributeName.indexOf("同") != -1) {
                                handleNoAttributeName(attributeName, category);
                            } else {
                                // 保存属性
                                handleAttributeName(category, item);
                            }
                        } else {
                            log.warn("类目名：{}，未找到类目数据", className);
                        }
                    });
                }
                // 初始化固定的物料的属性数据
//                    initMaterialAttributeMd(phMaterialPropertyValueMds);
            });
        }
    }

    /**
     * 保存属性名中不包含"同"字样数据
     *
     * @param category
     * @param item
     */
    private void handleAttributeName(PhCategory category, InventoryAttributeDataHeader item) {
        PhProperty property = initPropertyValue(item);
        boolean save = phPropertyService.save(property);
        // 保存类目与属性关系
        saveCategoryPropertyMdData(category.getId(), property.getId());

        // 保存属性值
        if (save && StringUtils.isNotBlank(item.getAttributeData())) {
            // 判断属性值里是否包含 "同XXX" 什么字样
            if (item.getAttributeData().indexOf("同") != -1) {
                handleNoAttributeData(property, item);
            } else {
                // 保存Excel里有写好的属性值数据
                saveAttributeData(item.getAttributeData(), property, new ArrayList<>());
            }
        }
    }


    /**
     * 处理属性为 "同XXX" 的数据
     *
     * @param attributeName
     */
    private void handleNoAttributeName(String attributeName, PhCategory currentCategory) {
        // 属性名
        String name = getNameByString(attributeName, "同");
        // 查询要复制的分类
        QueryWrapper wrapper1 = new QueryWrapper();
        wrapper1.eq("name", name);
        wrapper1.eq("level", 3);
        PhCategory phCategory = (PhCategory) phCategoryService.list(wrapper1).get(0);
        if (ObjectUtils.isNotEmpty(phCategory)) {
            QueryWrapper wrapper = new QueryWrapper();
            wrapper.eq("category_id", phCategory.getId());
            List<PhCategoryPropertyMd> categoryPropertyMds = phCategoryPropertyMdService.list(wrapper);
            for (PhCategoryPropertyMd propertyMd : categoryPropertyMds) {
                // 查询之前类目的属性
                PhProperty finalProperty = phPropertyService.getById(propertyMd.getPropertyId());

                // 保存当前类目的属性
                PhProperty newProperty = new PhProperty();
                BeanUtils.copyProperties(finalProperty, newProperty);
                newProperty.setId(null);
                phPropertyService.save(newProperty);

                // 保存类目与属性关系
                saveCategoryPropertyMdData(currentCategory.getId(), newProperty.getId());

                // 查询之前属性的属性值
                List<PhPropertyValue> propertyValues = getPropertyValueByPropertyId(finalProperty.getId());
                // 保存新属性与属性值关系
                propertyValues.stream().forEach(item1 -> {
                    savePhPropertyValue(newProperty, item1.getValue());
                });
            }
        }
    }

    /**
     * 初始化固定的物料数据
     *
     * @param phMaterialPropertyValueMds
     */
    private void initMaterialAttributeMd(List<PhMaterialPropertyValueMd> phMaterialPropertyValueMds) {
        // 初始化物料的属性数据
        QueryWrapper wrapper = new QueryWrapper();
//                    wrapper.eq("category_id", category.getId());
        wrapper.eq("material_code", "1000120210729212736297245");
        List<Material> material = materialService.list(wrapper);
        material.stream().forEach(materialDto -> {
            phMaterialPropertyValueMds.stream().forEach(mdsItem -> {
                mdsItem.setMaterialId(materialDto.getId());
                phMaterialPropertyValueMdService.save(mdsItem);
            });
        });
    }

    private String getNameByString(String str, String flag) {
        return str.substring(str.indexOf(flag) + 1, str.length());
    }

    /**
     * 处理属性值写有 "同XXX"的数据
     *
     * @param attributeDataHeader
     */
    private void handleNoAttributeData(PhProperty property, InventoryAttributeDataHeader attributeDataHeader) {
        // 1. 取出"同" 字后的 属性名称
        String attributeName = getNameByString(attributeDataHeader.getAttributeData(), "同");

        // 2. 查询数据库已存属性数据的属性值
        QueryWrapper wrapper = new QueryWrapper();
        wrapper.eq("name", attributeName);
        PhProperty phProperty = (PhProperty) phPropertyService.list(wrapper).get(0);

        List<PhPropertyValue> phPropertyValues = getPropertyValueByPropertyId(phProperty.getId());
        // 3.然后插入到当前属性数据中
        phPropertyValues.stream().forEach(propertyValue -> {
            savePhPropertyValue(property, propertyValue.getValue());
        });
    }

    /**
     * 保存Excel里有写好的属性值数据
     *
     * @param attributeData
     * @param property
     * @param phMaterialPropertyValueMds
     */
    private void saveAttributeData(String attributeData, PhProperty property, List<PhMaterialPropertyValueMd> phMaterialPropertyValueMds) {
        String[] attributeDataArray = attributeData.trim().split("、");
        if (null != attributeDataArray && attributeDataArray.length > 0) {
            for (String s : attributeDataArray) {
                PhPropertyValue propertyValue = savePhPropertyValue(property, s);
                // 汇总关系数据
                //phMaterialPropertyValueMds.add(initPhMaterialPropertyValueMdData(property, propertyValue));
            }
        }
    }

    /**
     * 初始化物料属性值中间表对象
     *
     * @param property
     * @param propertyValue
     * @return
     */
    private PhMaterialPropertyValueMd initPhMaterialPropertyValueMdData(PhProperty property, PhPropertyValue propertyValue) {
        PhMaterialPropertyValueMd materialPropertyValueMd = new PhMaterialPropertyValueMd();
        // 属性ID
        materialPropertyValueMd.setPropertyId(property.getId());
        // 属性名称
        materialPropertyValueMd.setPropertyName(property.getName());
        // 属性值
        materialPropertyValueMd.setPropertyValue(propertyValue.getValue());
        // 属性值ID
        materialPropertyValueMd.setValueId(propertyValue.getId());
        materialPropertyValueMd.setMaterialId(null);
        return materialPropertyValueMd;
    }

    private void saveCategoryPropertyMdData(Long categoryId, Long propertyId) {
        PhCategoryPropertyMd phCategoryPropertyMd = new PhCategoryPropertyMd();
        phCategoryPropertyMd.setCategoryId(categoryId);
        phCategoryPropertyMd.setPropertyId(propertyId);
        phCategoryPropertyMdService.save(phCategoryPropertyMd);
    }

    private PhPropertyValue savePhPropertyValue(PhProperty property, String propertyValue) {
        PhPropertyValue value = new PhPropertyValue();
        value.setPropertyId(property.getId());
        value.setSort(100);
        value.setStatus(YesOrNoEnum.YES.getCode());
        value.setValue(propertyValue);
        value.setCreatedTime(LocalDateTime.now());
        value.setUpdatedTime(LocalDateTime.now());
        phPropertyValueService.save(value);
        return value;
    }

    private List<PhCategory> getCategoryListByFirstClassName(String name) {
        // 查询分类ID
        QueryWrapper wrapper = new QueryWrapper();
        wrapper.eq("level", 1);
        wrapper.eq("name", name);
        // 查询一级分类
        PhCategory one = phCategoryService.getOne(wrapper);
        // 查询三级分类
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("parent_id", one.getId());
        queryWrapper.eq("level", 3);
        List<PhCategory> categoryList = phCategoryService.list(queryWrapper);
        return categoryList;
    }

    private PhProperty initPropertyValue(InventoryAttributeDataHeader attributeDataHeader) {
        LocalDateTime nowTime = LocalDateTime.now();
        // 保存属性数据
        PhProperty phProperty = new PhProperty();
        phProperty.setName(attributeDataHeader.getAttributeName());
        phProperty.setAliasName("");
        // 值录入方式：1单行文本框，2下拉单选，3单选，4复选, 5多行文本框， 6下拉多选
        phProperty.setInputMethod(Integer.parseInt(attributeDataHeader.getInputMode()));
        phProperty.setIsRequired(Integer.parseInt(attributeDataHeader.getIsRequired()));
        phProperty.setType(PropertyTypeEnum.INVENTORY.getCode());
        phProperty.setStatus(YesOrNoEnum.YES.getCode());
        phProperty.setCreatedTime(nowTime);
        phProperty.setUpdatedTime(nowTime);
        return phProperty;
    }

    private List<PhPropertyValue> getPropertyValueByPropertyId(Long propertyId) {
        QueryWrapper wrapper = new QueryWrapper();
        wrapper.eq("property_id", propertyId);
        return phPropertyValueService.list(wrapper);
    }
}
